import sys
from typing import overload

import fuzzywuzzy.fuzz as fz
# import numpy as np
# from PyQt5.Qt import QCompleter
from PyQt5 import QtCore  # , QtGui, QtWidgets
from PyQt5.Qt import QStandardItemModel
from PyQt5.QtCore import QModelIndex, pyqtProperty, QPropertyAnimation, QTimer, QThread
from PyQt5.QtGui import QKeySequence, QStandardItem, QColor, QBrush, QFont, QPalette, QTextCursor
from PyQt5.QtWidgets import QApplication, QHeaderView, QStatusBar, QLabel, QPushButton, QStyle, QShortcut, QMessageBox, \
    QSizePolicy
from PyQt5.QtWidgets import QMainWindow
# from numpy.core.defchararray import isnumeric

from utility import banks_load_for
# from View import interface
from ui.JarvisWin import Ui_MainWindow
from Jarvis import *
import re
import audio as ad


agents = banks_load_for('all_agent_count')  # pd.frame
sentTo = banks_load_for('sentTo')
alias = banks_load_for('alias_agent')  # dic
workers = banks_load_for('worker')
approve = banks_load_for(kApprove)
owners = banks_load_for(kOwner)
contents = banks_load_for(kCon)
banks_map = {kAgent: agents,
             kSent: sentTo,
             kApprove: approve,
             kWorker: workers,
             kCon: contents,
             kOwner: owners}
for b in banks_map:
    bank = banks_map[b]
    bank['key'] = bank.index
    bank['count'] = bank['count']/bank['count'].max()

map_book = {'。': '',
            '空格': ' ',
            '回车': '\n', '换行': '\n',
            '逗号': '，',
            '杠': '——',
            '冒号': '：',
            '括号': '（',
            '点': '.',
            '退格': '\b',
            '？': ' ', '，': ' ', '！': ' ', 'ã€‚': ' ',
            '零': '0', '一': '1', '二': '2', '三': '3', '四': '4',
            '五': '5', '六': '6', '七': '7', '八': '8', '九': '9'
            }


def get_field_from(s):
    # extract the number
    s = re.sub(r' +', ' ', s)
    s = re.sub(r'\n+', '\n', s)

    res = re.findall('[\s]+\d{1,3}[\s]', s)
    if res:
        number = re.findall('\d+', res[0])[0]
        s = s.replace(res[0], res[0][-1])
    else:
        number = ''
    lines = s.split('\n')
    lines = list(filter(lambda s: s.strip() != '', lines))
    n = len(lines)
    if n < 1:
        return None
    if s[-1] == '\n':
        lines.append('')
        n += 1
    fields = {'agent': '',
              'sentTo': '',
              'approve': '',
              'worker': '',
              'owner': '',
              'content': '',
              kNum: number,
              'now': '',
              'next': '用章单位',
              'newLine': False}
    if n < 1:
        return fields
    if ' ' in lines[0]:
        ss = lines[0].split(' ')
        n2 = len(ss)
        fields[kAgent] = ss[0]
        fields['next'] = '发往单位'
        if n2 > 1:
            fields[kSent] = ss[1]
            fields['now'] = '发往单位'
            fields['next'] = '批准单位'
        if n2 > 2:
            fields[kApprove] = ss[2]
            fields['now'] = '批准单位'
            fields['next'] = '内容'
            fields['newLine'] = True
    else:
        fields['now'] = '用章单位'
        fields['agent'] = lines[0]
        fields['next'] = '发往单位'

    # here finish agent []
    if n < 2:
        return fields
    fields[kCon] = lines[1]
    fields['now'] = '内容'
    fields['next'] = '经办人'
    fields['newLine'] = True
    if n < 3:
        return fields
    fields['newLine'] = False
    if ' ' in lines[2]:
        ss = lines[2].split(' ')
        fields[kWorker] = ss[0]
        fields['now'] = '经办人'
        fields['next'] = '申请人'
        if len(ss) > 1:
            fields[kOwner] = ss[1]
            fields['now'] = '申请人'
            fields['next'] = '用章数量'
            fields['newLine'] = True
    else:
        fields[kWorker] = lines[2]
        fields['now'] = '经办人'
        fields['next'] = '申请人'

    if fields['next'] == '用章数量' and fields[kNum] != '':
        fields['next'] = 'done'
    return fields


def sort_result_by_name(word: str, results: list) -> list:
    res2 = []
    for r in results:
        if r.startswith(word):
            res2.append(r)
    for r in res2:
        results.remove(r)
    res2.extend(results)
    return res2


def search_in(word: str, field: str, ratio_threshold='auto', result_limit=10):
    if word[0] == '-':
        return []
    result = []
    if field not in banks_map:
        return [word]
    bank = banks_map[field]
    if ratio_threshold == 'auto':
        if len(word) <= 3 or len(word) >= 8:
            ratio_threshold = 50
        else:
            ratio_threshold = 40
    ks = bank['key']
    # weights [0.3,0.3,0.3]
    s1 = ks.apply(lambda x: 0.5*fz.partial_ratio(x, word) +
                  0.3*fz.ratio(x, word))
    # s2 = ks.apply(lambda x: fz.ratio(x, word))
    bank['s'] = s1 + bank['count']*20

    sorted_items = bank.sort_values(by='s', ascending=False)
    ks = sorted_items.index

    if sorted_items.loc[ks[0], 's'] < ratio_threshold:
        result.append(word)

    for i in range(result_limit):
        result.append(ks[i])
    # for i in sorted_items.index:
    #     if sorted_items.loc[i, 's'] > ratio_threshold:
    #         result.append(sorted_items.loc[i, 'key'])
    #         if len(result) > result_limit: break
    # for agent in sorted:#bank.index:
    #     if type(agent) is not str: continue
    #     d = fz.partial_ratio(agent, word)
    #     if d > ratio_threshold:
    #         result.append(agent)
    #         if len(result) > result_limit: break
    return sort_result_by_name(word, result)


class MainWindow(QMainWindow, Ui_MainWindow):

    def __init__(self):

        super(MainWindow, self).__init__(None)
        self.waiting_on_timer = False
        self.ks_col = {}
        self.col_ks = [kAgent, kSent, kApprove, kCon, kWorker, kOwner]
        self.block_flags = {}
        for i, k in enumerate(self.col_ks):
            self.ks_col[k] = i
            self.block_flags[k] = False

        self.model = QStandardItemModel()
        self.setupUi(self)
        # self.statusbar.show
        self.statusBar().showMessage('嗨，别来无恙')

        self.setWindowTitle('Jarvis')
        self.add_table_header()
        self.textEdit_2.cursorPositionChanged.connect(self.event_cur_changed)
        # self.selected_fields = [''] * 6
        self.selected_fields_ = {'agent': '',
                                 'sentTo': '',
                                 'approve': '',
                                 'worker': '',
                                 'owner': '',
                                 'content': '',
                                 kNum: ''}
        self.history = self.selected_fields_.copy()
        self.last_fields_ = {'agent': '',
                             'sentTo': '',
                             'approve': '',
                             'worker': '',
                             'owner': '',
                             'content': '',
                             kNum: ''}
        self.last_text = ''

        self.anim = QPropertyAnimation(self, b"status_color")
        self.doAnim()

        if ad.avaliable:
            self.audio_thread = ad.MicRecognize()
            self.audio_thread.detected_words.connect(self.audio_in)
            self.audio_thread.doing.connect(self.audio_record_or_stop)

            self.audio_thread2 = ad.MicRecognize()
            self.audio_thread2.detected_words.connect(self.audio_in)
            self.audio_thread2.doing.connect(self.audio_record_or_stop)
            self.audio_thread.start()
            self.audio_thread2.start()

            self.remote_label = QPushButton('远程输出')
            self.statusbar.addPermanentWidget(self.remote_label)
            self.remote_label.setStyleSheet("border:0px;")
            self.remote_label.pressed.connect(self.event_switch_remote)
            self.to_remote = False
            q = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
            self.remote_label.setSizePolicy(q)

        else:
            self.audio_thread = ad.RemoteListen()
            self.audio_thread.detected_words.connect(self.audio_in)
            self.audio_thread.doing.connect(self.audio_record_or_stop)
            self.audio_thread.start()

        self.ststus_label = QPushButton('语音控制')
        self.statusbar.addPermanentWidget(self.ststus_label)
        self.ststus_label.setStyleSheet("border:0px;")
        self.ststus_label.pressed.connect(self.event_switch_audio)

        q = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.ststus_label.setSizePolicy(q)
        # statusB->addPermanentWidget(per1); // 现实永久信息

        self.key_shortcut()

    def key_shortcut(self):
        self.msgSc = QShortcut(QKeySequence('Ctrl+M'), self)
        self.msgSc.activated.connect(self.event_switch_audio)

        # self.msgSc = QShortcut('Ctrl+L', self)
        # self.msgSc.activated.connect(self.event_action_auto_complete)

        # msgSc3 = QShortcut('Alt+Left', self)
        # msgSc3.activated.connect(self.action_to_last)

        # self.msgSc = QShortcut(QKeySequence('Ctrl+,'), self.textEdit_2)#,context=QtCore.Qt.WindowShortcut)

        # self.msgSc.activated.connect(
        #     self.event_action_auto_complete)
        # lambda : QMessageBox.information(self,
        # 'Message', 'Ctrl + M initiated'))

        # a = QShortcut(self)

        # key_id = self.grabShortcut('Ctrl+Space')
        # self.releaseShortcut(key_id)
        # if not a.setKey('Ctrl+shift+Space'):
        #     print('space failed')
        # else:
        #     pass
        # a.activated.connect(lambda: print('space trig'))
        # QShortcut(QKeySequence('ctrl+Space,ctrl+Space'), self).activated.connect(lambda: print('trig'))
        # QShortcut(QKeySequence('Ctrl+n'), self).activated.connect(self.textEdit_2.clear)

    def doAnim(self):
        self.anim.setDuration(30000)
        self.anim.setStartValue(QColor(221, 239, 217))  # 粉色
        self.anim.setKeyValueAt(0.25, QColor(190, 250, 176))  # 红色
        self.anim.setKeyValueAt(0.5, QColor(205, 255, 158))  # 红色
        self.anim.setKeyValueAt(0.75, QColor(214, 106, 91))
        self.anim.setEndValue(QColor(221, 239, 217))  # 米黄

        self.anim.setLoopCount(-1)
        self.anim.start()

    def play_done(self):
        self.waiting_on_timer = False
        self.doAnim()

    def show_warning(self, msg: str):
        self.anim.stop()
        self.anim.setDuration(8000)
        self.anim.setStartValue(QColor(20, 191, 204))  # 粉色
        self.anim.setKeyValueAt(0.5, QColor(214, 106, 91))
        self.anim.setEndValue(QColor(221, 239, 217))  # 米黄
        self.anim.setLoopCount(1)
        self.anim.start()
        self.show_msg(msg)
        # print('\a')
        if not self.waiting_on_timer:
            QTimer.singleShot(10000, self.play_done)
            self.waiting_on_timer = True

    def show_msg(self, msg: str):
        if not self.waiting_on_timer:
            self.statusbar.showMessage(msg, -1)
        else:
            s = self.statusbar.currentMessage()
            s += ' // ' + msg
            self.statusbar.showMessage(s, -1)

    def add_table_header(self):
        self.tableView.setModel(self.model)
        for i, header in enumerate('申请单位 发往单位 批准单位 内容 经办人 申请人'.split(' ')):
            m = QStandardItem(header)
            # m.setForeground(QColor(255,255,255))
            m.setBackground(QBrush(QColor(3, 147, 176, 80)))
            m.font().setBold(True)

            self.model.setHorizontalHeaderItem(i, m)
            # self.model.horizontalHeaderItem(i).setBackground(QColor(89, 168, 105))

        self.model.setRowCount(20)
        for i in range(20):
            for j in range(len(self.ks_col)):
                self.model.setItem(i, j, QStandardItem(''))
        for i in range(len(self.ks_col)):
            # self.model.item(0, i).setBackground(QColor(3, 147, 176, 80))
            f = self.model.item(0, i).font()
            f.setBold(True)
            f.setPointSize(f.pointSize() + 2)
            self.model.item(0, i).setFont(f)
        self.tableView.horizontalHeader().setSectionResizeMode(
            self.ks_col[kCon], QHeaderView.Stretch)

    def event_cur_changed(self):
        try:
            text = self.textEdit_2.toPlainText()
            if self.last_text == text:  # no change
                return
            if text == '':
                self.last_text = ''
                return
            n = self.textEdit_2.textCursor().anchor() - 1
            c = text[n]
            if n > 0 and len(text) > len(self.last_text) and c == '\n' and text[n - 1] == '\n':
                s = text.replace('\n', '')
                if s != '' and self.selected_fields_[kCon] == '':
                    # try assistant
                    ok, msg = append_last_number(s)
                    if not ok:
                        self.show_warning(msg)
                    else:
                        self.show_msg('上一行[用章数量]:' + msg)
                        self.textEdit_2.clear()
                else:
                    self.event_button_clicked()
                self.last_text = text
                return

            self.last_text = text
            done = self.parse_text(text)
            if done and c == '\n':
                self.event_button_clicked()
        except Exception as e:
            print(e)

    def action_to_last(self):
        for k in self.history:
            self.selected_fields_[k] = self.history[k]

        d = self.selected_fields_
        s = d[kAgent] + ' ' + d[kSent] + ' ' + d[kApprove] + '\n' + d[kCon] + ' ' + d[kNum] + ' \n' + d[kWorker] + ' ' + \
            d[kOwner]
        self.textEdit_2.setText(s)
        self.textEdit_2.moveCursor(QTextCursor.End)

    def event_table_clicked(self, m: QModelIndex):
        # print(m)
        i = m.row()
        if i == 0:
            return
        j = m.column()
        s = self.model.item(i, j).text()
        # print('clicked:', s)
        if s != '':
            if self.selected_fields_[self.col_ks[j]] != s:
                self.selected_fields_[self.col_ks[j]] = s
                self.block_flags[self.col_ks[j]] = True
            else:
                # block this field
                self.block_flags[self.col_ks[j]
                                 ] = not self.block_flags[self.col_ks[j]]
            self.show_out()
            if self.block_flags[self.col_ks[j]]:
                self.model.item(0, j).setBackground(QColor(3, 147, 176, 80))
            else:
                self.model.item(0, j).setBackground(QColor(255, 255, 255))

    def event_table_entered(self, m: QModelIndex):
        i = m.row()
        if i != 0:
            return
        j = m.column()

        self.block_flags[self.col_ks[j]] = True  # block this field
        self.model.item(0, j).setBackground(QColor(3, 147, 176, 80))

    def event_switch_remote(self):
        self.to_remote = not self.to_remote
        if self.to_remote:
            self.audio_thread.to_remote()
            self.audio_thread2.to_remote()
            self.remote_label.setStyleSheet(
                "background-color:red;border-radius:7px;")

        else:
            self.audio_thread.detected_words.connect(self.audio_in)
            self.audio_thread2.detected_words.connect(self.audio_in)
            self.remote_label.setStyleSheet("border:0px;")

    def event_switch_audio(self):
        
        self.audio_thread.need_run = not self.audio_thread.need_run
        if ad.avaliable:
            self.audio_thread2.need_run = self.audio_thread.need_run

        if self.audio_thread.need_run:
            ad.sem.release()
            if ad.avaliable:
                ad.sem.release()
            
            # self.ststus_label.setStyleSheet("background-color:red;border-radius:7px;")
            self.ststus_label.setText(' 录音中 ')
        else:
            # self.ststus_label.setStyleSheet("border:0px;")
            self.ststus_label.setText('语音控制')
                
        # print('action')

    def audio_record_or_stop(self, msg: str):
        if msg == 'recording':
            self.ststus_label.setStyleSheet(
                "background-color:red;border-radius:7px;")
        else:
            self.ststus_label.setStyleSheet("border:0px;")

    def event_action_auto_complete(self):
        con = self.textEdit_2.toPlainText()
        for i, k in enumerate(self.col_ks):
            s = self.model.item(1, i).text()
            con = con.replace(s, self.selected_fields_[k])
        self.textEdit_2.setText(con)
        self.textEdit_2.moveCursor(QTextCursor.End)

    def event_action_auto_complete_all(self):
        print('action2')

    def audio_in(self, words: str):
        if words == '':
            return

        for k in map_book:
            if k in words:
                words = words.replace(k, map_book[k])
        s = self.textEdit_2.toPlainText()
        s += words
        n = self.textEdit_2.textCursor().anchor()
        self.textEdit_2.setText(s)
        self.textEdit_2.moveCursor(QTextCursor.End)

    def guess_field(self):
        if self.selected_fields_[kApprove] == '':
            con = self.selected_fields_[kCon]
            maybe = '科发院'
            book = {'退休': '离退休办','培训班结业证':'继教院',"聘任":'人事部'}
            for b in book:
                if b in con:
                    maybe = book[b]
                    break
            if '证书' in con and ('硕' in con or '博' in con):
                maybe = '研究生院'
            self.selected_fields_[kApprove] = maybe
            self.show_warning('[批准单位]缺省, 填充为: ' + maybe)

    def event_button_clicked(self):
        # self.but_anim.start()
        if self.selected_fields_[kAgent] == '':
            self.show_warning('[用章单位]为空')
        if self.selected_fields_[kCon] != '':
            self.guess_field()
        for i, k in enumerate(self.ks_col):
            self.selected_fields_[k] = self.selected_fields_[
                k].replace('_', ' ')
            if self.selected_fields_[k] == '-':
                self.selected_fields_[k] = ''
            if not self.block_flags[k]:
                continue
            self.selected_fields_[k] = self.model.item(0, i).text()
            self.block_flags[k] = False
            self.model.item(0, i).setBackground(QColor(255, 255, 255))
        if self.selected_fields_[kOwner] == '--':
            self.selected_fields_[kOwner] = self.selected_fields_[kWorker]
        ok, msg, num = add_a_record(self.selected_fields_)

        if not ok:
            self.show_warning(msg)
            return
        self.textEdit_2.clear()
        change = False
        for i, k in enumerate(self.ks_col):
            if self.selected_fields_[k] != '':
                self.history[k] = self.selected_fields_[k]
                self.selected_fields_[k] = ''
                change = True
            self.last_fields_[k] = ''
        if not change:
            self.show_warning('空表单')
        self.label.setText(num)

    def parse_text(self, s: str):
        s = s.replace('\t', ' ')
        field = get_field_from(s)
        if field is None:
            return
        s = ''
        if field['now'] != '':
            s = '当前项目: ' + field['now'] + ', '

        if field['newLine']:
            s += ' 回车, '
        if field['next'] == 'done':
            s += '完成, 回车确认'
        else:
            s += '下一项目: ' + field['next']
        self.show_msg(s)
        update = False

        for k in self.ks_col:
            if self.block_flags[k]:
                continue  # skip this field
            col = self.ks_col[k]
            a = field[k]
            if a == '' and self.selected_fields_[k] == '':
                continue

            if a == '':
                self.selected_fields_[k] = ''
                update = True
                continue

            if k == kCon and '——' in a:
                a = a[:a.index('——')]
                s = field[kCon]
                s = s[s.index('——') + 2:]
                s1 = self.selected_fields_[kCon]
                if '——' in s1:
                    n = s1.index('——')
                    s1 = s1[:n]
                    s2 = s1[n + 2:]
                    if s2 != s:
                        self.selected_fields_[kCon] = s1 + '——' + s
                        update = True
                else:
                    self.selected_fields_[kCon] = s1 + '——' + s
                    update = True

            if a == self.last_fields_[k]:
                continue
            self.last_fields_[k] = a

            maybe = search_in(a, k)
            self.model.item(1, col).setText(a)
            for i, b in enumerate(maybe):
                self.model.item(i + 2, col).setText(b)
            if len(maybe) == 0 and self.selected_fields_[k] != a:
                self.selected_fields_[k] = a
                update = True
            elif len(maybe) > 0 and self.selected_fields_[k] != maybe[0]:
                self.selected_fields_[k] = maybe[0]
                update = True
            # for content
            if k == kCon and '——' in field[kCon]:
                s = field[kCon]
                self.selected_fields_[kCon] += s[s.index('——'):]
                update = True
        k = kNum
        if self.selected_fields_[k] != field[k]:
            self.selected_fields_[k] = field[k]
            update = True
        if update:
            self.show_out()
            # self.selected_fields = field
        if field['next'] == 'done':
            return True
        return False

    
    def show_out(self):
        self.textEdit.clear()
        c = self.textEdit.textCursor()
        
        s = ''
        # <h1><font color = green>%1</font>的人品指数：<font color = orange>%2</font>
        fs = self.selected_fields_
        s = fs[kAgent] + ' <font color = green blod = True><b>&nbsp;&nbsp;发往</b></font> ' + fs[kSent] + '\t'
        if fs[kApprove] != '':
            s += '<font color = green><b>&nbsp;&nbsp;批准</b></font>' + fs[kApprove]

        if fs[kNum] != '':
            s += '<font color = green><b>&nbsp;&nbsp;#</b></font>' + fs[kNum]
        if fs[kWorker]:
            s += '<font color = green><b>&nbsp;&nbsp;&nbsp;&nbsp;人员:</b></font>'+ (fs[kWorker])
        if fs[kOwner] != '':
            s += '（' + fs[kOwner] + ' '
        if fs[kCon]:
            s += '<br><font color = green><b>内容:</b></font>' + fs[kCon]

        # self.textEdit.setText(s)
        c.insertHtml(s)
        for i, k in enumerate(self.col_ks):
            self.model.item(0, i).setText(self.selected_fields_[k])

    def _set_bar_color(self, col):
        r, g, b, _ = col.getRgb()
        self.statusbar.setStyleSheet(
            'color:rgb(255, 255, 255);'
            "background-color:hsv(%d, %d,%d);" % (r, g, b))
    
    status_color = pyqtProperty(QColor, fset=_set_bar_color)




if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    mainWindow.activateWindow()
    mainWindow.raise_()
    app.exec_()
    del mainWindow
    del app
